package NIO.blocking;
/*
 * @Author  Wrial
 * @Date Created in 11:01 2020/4/11
 * @Description 使用nio包下的类创建阻塞式的Server
 */

import java.io.*;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class BlockingServer {

    public static void main(String[] args) throws IOException {
        new BlockingServer(8090).service();
    }


    private static final int THREADS = 5;
    private int port;
    private ServerSocketChannel sSC;
    private ExecutorService executorService;

    public BlockingServer(int port) throws IOException {
        init(port);
    }

    // 服务端的初始化
    private void init(int port) throws IOException {
        this.port = port;
        sSC = ServerSocketChannel.open();
        // 设置端口复用 一般只有在多播时有用到
        sSC.socket().setReuseAddress(true);
        // 绑定本地端口
        sSC.socket().bind(new InetSocketAddress(8090));
        // 根据处理器情况创建固定的线程池大小
        executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * THREADS);
        System.out.println("Blocking Server init in port " + port);
    }

    public void service() throws IOException {
        while (true) {
            SocketChannel socketChannel;
            socketChannel = sSC.accept();
            executorService.submit(new HandleTask(socketChannel));
        }
    }


    // 因为采用的是阻塞方式，因此每个任务都需要一个线程来完成
    class HandleTask implements Runnable {
        // 服务端accept一定会获取到客户端的socketChannel
        private SocketChannel socketChannel;

        public HandleTask(SocketChannel socketChannel) {
            this.socketChannel = socketChannel;
        }

        public void run() {
            try {
                handle(socketChannel);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        private void handle(SocketChannel socketChannel) throws IOException {
            Socket socket = socketChannel.socket();
            System.out.println("receive from " + socket.getInetAddress());
            BufferedReader reader = getBufferReader(socket);
            PrintWriter writer = getPrintWriter(socket);

            String msg;
            while ((msg = reader.readLine()) != null) {
                writer.println(receiveAndEchoMsg(msg,socket.getInetAddress()));
                if (msg.equals("end")) {
                    System.out.println("结束会话");
                    break;
                }
            }
            if (socketChannel != null) socketChannel.close();

        }

        private String receiveAndEchoMsg(String msg, InetAddress inetAddress) {
            System.out.println("receive msg from client address : "+inetAddress.getHostName() +"  msg : "+ msg);
            return "echo from server : " + msg;
        }

        private PrintWriter getPrintWriter(Socket socket) throws IOException {
            OutputStream outputStream = socket.getOutputStream();
            return new PrintWriter(outputStream,true);

        }

        private BufferedReader getBufferReader(Socket socket) throws IOException {
            InputStream inputStream = socket.getInputStream();
            return new BufferedReader(new InputStreamReader(inputStream));
        }


    }


}
